<?php
/**
 * Created by PhpStorm.
 * User: Inhere
 * Date: 2015/1/30
 * Use : ...
 * File: AbstractDatastorage.php
 */

namespace ulue\libs\datastorage;

use Symfony\Component\Yaml\Yaml;
use ulue\libs\datastorage\helpers\DataHelper;
use ulue\libs\helpers\FormatHelper;
use ulue\libs\helpers\ObjectHelper;

abstract class AbstractDatastorage extends AbstractDataOperator
{

    /**
     * 载入数据支持格式 @see DataOption
     */

    /**
     * 载入文件支持格式  @see DataOption
     * 'json' 'yml' -- string
     * 'php' 'inc' 'conf' -- array
     */

    /**
     * 全部配置数据
     * 配置名 => 配置值
     * @var array
     */
    protected $box = [];

    /**
     * 设置配置数据($box)的键名(配置名)是否统一格式
     * DataOption::CASE_RAW 不做任何改变
     * DataOption::CASE_LOWER 设置全部小写
     * DataOption::CASE_UPPER 设置全部大写
     * @var int
     */
    protected $keyCase = -1;

    /**
     * @param string $input
     * @param string $format
     */
    public function __construct($input='',$format='php')
    {
        $this->loadData($input,$format);
    }

    /**
     * @param $input
     * @param string $format
     * @return bool
     * @throws \DFileSystemException
     * @throws \DInvalidArgumentException
     * @throws \DMissArgumentException
     */
    protected function loadData($input, $format='php')
    {
        if (empty($input)) {
            return false;
        }

//        $this->_verifyFormat($format);

        switch ( $format ) {
            case DataOption::JSON_FORMAT:
            case DataOption::YAML_FORMAT:
                $this->loadString($input, $format);
                break;
            case DataOption::OBJECT_FORMAT:
                $this->loadObject($input);
                break;
            case DataOption::ARRAY_FORMAT:
                $this->bindData($input);
                break;
            case DataOption::PHP_FILE:
                $this->loadArray($input);
                break;
            default :
                throw new \DInvalidArgumentException( sprintf('%s不是受支持的配置数据格式！',$format) );
                break;
        }

        return true;
    }

    public function loadString($input, $format='json')
    {
        $input = trim($input);

        if (strpos($input, "\n") === false && is_file($input)) {
            if (false === is_readable($input)) {
                throw new \DFileSystemException(sprintf('Unable to parse "%s" as the file is not readable.', $input), 'read');
            }

            $input = file_get_contents($input);
        }

        if ($format == DataOption::JSON_FORMAT ) {
            // clear annotation
            $input = FormatHelper::json($input);
        }

        if ($format == DataOption::JSON_FORMAT && ($jsonData = @json_decode($input,true)) != false ) {
            $array = $jsonData;
        } else if ( $format == DataOption::YAML_FORMAT ) {
            $array = Yaml::parse($input);
        } else {
            throw new \DMissArgumentException(sprintf('第二个参数"%s"是错误的，目前仅可设置为"json" "yml" 两种类型！',$format));
        }

        return $this->loadArray($array);
    }

    /**
     * @param $file
     * @param string $format
     * @return $this
     * @throws \DFileSystemException
     * @throws \DMissArgumentException
     */
    public function loadFile($file, $format='json')
    {
        if (!file_exists($file)) {
            \Trigger::error("数据文件 {$file} 不存在！请检查并正确设置。");
        }

        $this->loadData($file, $format);

        return $this;
    }

    /**
     * 载入数组格式的配置数据
     * @param string|array $array 可以是个文件路径，可返回配置数组 | 配置数组
     * @return \ulue\core\config\Configuration
     */
    public function loadArray($array)
    {
        if(is_string($array) && is_file($array)) {
            $array = require_once $array;
        }

        $this->bindData($array);

        return $this;
    }

    /**
     * 载入对象格式的配置数据
     * @param  $object
     * @throws \DInvalidArgumentException
     * @return $this
     */
    public function loadObject( $object)
    {
        if (!is_object($object)) {
            throw new \DInvalidArgumentException('参数类型必须是个对象!');
        }

        if ($object instanceof \stdClass) {
            $data = ObjectHelper::toArray($object);
        } else {
            $data = get_object_vars($object);
        }

        $this->bindData($data);

        return $this;
    }

    /**
     * 绑定数据到 @see $box 中
     * @param array $array
     * @return $this
     */
    public function bindData(array $array)
    {
        #是个数组,合并配置
        if ( is_array($array) && !empty($array) ) {
            if ( $this->keyCase !== DataOption::CASE_RAW ) {
                $array = array_change_key_case($array, $this->keyCase);
            }

            $this->box = DataHelper::mergeArrays((array)$this->box, $array);
        }
    }

    /**
     * @see $keyCase
     * @param int $value
     */
    public function keyCase($value=-1)
    {
        if ( in_array(
            (int) $value,
            [ DataOption::CASE_RAW, DataOption::CASE_UPPER, DataOption::CASE_LOWER ]
        ) ) {
            $this->keyCase = (int) $value;
        }
    }


}// end class AbstractDatastorage